﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using Arborium;
using System.IO;
using Microsoft.Win32;

namespace ArboriumExplorer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        #region Private Members

        private AElement _arboriumTree;
        private TreeViewItem _tree;
        private TreeViewItem _selectedItem;
        private Dictionary<TreeViewItem, AElement> _route;

        #endregion

        public MainWindow()
        {
            InitializeComponent();

            treeView.SelectedItemChanged += TreeViewOnSelectedItemChanged;

            string[] args = Environment.GetCommandLineArgs();
            if (args.Length > 1)
            {
                string filename = args[1];
                _arboriumTree = AElement.Load(filename);
                RefreshTree();
                Title = filename;
            }
        }

        #region Event handlers

        private void TreeViewOnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> routedPropertyChangedEventArgs)
        {
            Mouse.SetCursor(Cursors.Wait);

            StringBuilder convertedData = new StringBuilder();
            StringBuilder convertedMetadata = new StringBuilder();

            _selectedItem = (TreeViewItem)routedPropertyChangedEventArgs.NewValue;

            if (_selectedItem == null)
            {
                return;
            }

            Conversions.TryToDecode(convertedData, convertedMetadata, _route[_selectedItem]);

            FlowDocument document = new FlowDocument();

            Paragraph dataHeaderParagraph = new Paragraph { Foreground = Brushes.MediumBlue };
            dataHeaderParagraph.Inlines.Add(new Bold(new Run("Data")));

            Paragraph dataParagraph = new Paragraph();
            dataParagraph.Inlines.Add(new Run(convertedData.ToString()));

            Paragraph metadataHeaderParagraph = new Paragraph { Foreground = Brushes.MediumBlue };
            metadataHeaderParagraph.Inlines.Add(new Bold(new Run("Metadata")));

            Paragraph metadataParagraph = new Paragraph();
            metadataParagraph.Inlines.Add(new Run(convertedMetadata.ToString()));

            document.Blocks.Add(dataHeaderParagraph);
            document.Blocks.Add(dataParagraph);
            document.Blocks.Add(metadataHeaderParagraph);
            document.Blocks.Add(metadataParagraph);

            ValueBox.Dispatcher.Invoke(new Action(() =>
                {
                    ValueBox.Document = document;
                }));

            Mouse.SetCursor(Cursors.None);
        }

        private void LoadCommand(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog
            {
                FileName = "",
                DefaultExt = ".arbo",
                Filter =
                    "Arborium containers|*.arbo"
            };

            if (openDialog.ShowDialog() == true)
            {
                string filename = openDialog.FileName;
                _arboriumTree = AElement.Load(filename);
                RefreshTree();
                Title = filename;
            }
        }

        private void NewCommand(object sender, RoutedEventArgs e)
        {
            _arboriumTree = new AElement();
            RefreshTree();
            _selectedItem = _tree;
            Title = "(new)";
        }

        private void NewFromClipboardCommand(object sender, RoutedEventArgs e)
        {
            try
            {
                if (Clipboard.ContainsText())
                {
                    string text = Clipboard.GetText();

                    _arboriumTree = AElement.FromBase64String(text);
                    RefreshTree();
                    _selectedItem = _tree;
                    Title = "(new)";
                }
                else
                {
                    throw new Exception("No text data on the clipboard");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Could not create a tree: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Hand);
            }
        }

        private void SaveCommand(object sender, RoutedEventArgs e)
        {
            if (_arboriumTree != null)
            {
                SaveFileDialog saveDialog = new SaveFileDialog
                {
                    FileName = Title,
                    DefaultExt = ".arbo",
                    Filter = "Arborium containers|*.arbo"
                };

                if (saveDialog.ShowDialog() == true)
                {
                    string filename = saveDialog.FileName;
                    _arboriumTree.Save(filename);
                    Title = filename;
                }
            }
            else
            {
                MessageBox.Show("There is nothing to save. Load or create a tree!", "Error", MessageBoxButton.OK,
                                MessageBoxImage.Hand);
            }
        }

        private void AddCommand(object sender, RoutedEventArgs e)
        {
            if (IsItemSelected())
            {
                AElement newItem = new AElement();
                _route[_selectedItem].Add(newItem);
                EditNode(newItem);
                RefreshTree();
            }
        }

        private void EditCommand(object sender, RoutedEventArgs e)
        {
            if (IsItemSelected())
            {
                AElement selectedNode = _route[_selectedItem];
                EditNode(selectedNode);
                RefreshTree();
            }
        }

        private void DeleteCommand(object sender, RoutedEventArgs e)
        {
            if (IsItemSelected())
            {
                if (MessageBox.Show("You are going to delete a subtree. Are you really sure?", "Delete", MessageBoxButton.YesNo, MessageBoxImage.Question) ==
                    MessageBoxResult.Yes)
                {
                    AElement treeNode = _route[_selectedItem];

                    if (treeNode.Parent == null)
                    {
                        MessageBox.Show("It is not possible to delete the root element.", "Error", MessageBoxButton.OK, MessageBoxImage.Hand);
                    }
                    else
                    {
                        treeNode.Parent.Remove(treeNode);
                        RefreshTree();
                    }
                }
            }
        }

        private void AttachCommand(object sender, RoutedEventArgs e)
        {
            if (IsItemSelected())
            {
                OpenFileDialog openDialog = new OpenFileDialog
                    {
                        FileName = "",
                        DefaultExt = ".arbo",
                        Filter =
                            "Arborium containers|*.arbo"
                    };

                if (openDialog.ShowDialog() == true)
                {
                    string filename = openDialog.FileName;
                    AElement selectedNode = _route[_selectedItem];
                    AElement newTree = AElement.Load(filename);
                    selectedNode.Add(newTree);
                    RefreshTree();
                }
            }
        }

        private void DetachCommand(object sender, RoutedEventArgs e)
        {
            if (IsItemSelected())
            {
                SaveFileDialog saveDialog = new SaveFileDialog
                {
                    FileName = Title,
                    DefaultExt = ".arbo",
                    Filter =
                        "Arborium containers|*.arbo"
                };

                if (saveDialog.ShowDialog() == true)
                {
                    AElement selectedNode = _route[_selectedItem];
                    string filename = saveDialog.FileName;
                    selectedNode.Save(filename);
                    selectedNode.Parent.Detach(selectedNode);
                    RefreshTree();
                }
            }
        }

        private void FromClipboardCommand(object sender, RoutedEventArgs e)
        {
            try
            {
                if (IsItemSelected())
                {
                    if (Clipboard.ContainsText())
                    {
                        string text = Clipboard.GetText();

                        AElement selectedNode = _route[_selectedItem];
                        selectedNode.Add(AElement.FromBase64String(text));
                        RefreshTree();
                    }
                    else
                    {
                        throw new Exception("No text data on the clipboard");
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Could not create a tree: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Hand);
            }
        }

        private void ToClipboardCommand(object sender, RoutedEventArgs e)
        {
            try
            {
                if (IsItemSelected())
                {
                    AElement selectedNode = _route[_selectedItem];
                    string text = selectedNode.ToBase64String();
                    Clipboard.SetText(text);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Could not copy a (sub)tree to the clipboard: {0}", ex.Message), "Error", MessageBoxButton.OK, MessageBoxImage.Hand);
            }
        }


        #endregion

        #region Private methods

        private void RefreshTree()
        {
            _tree = new TreeViewItem();
            _route = new Dictionary<TreeViewItem, AElement>();
            CloneTree(_tree, _arboriumTree);
            treeView.Items.Clear();
            treeView.Items.Add(_tree);
            _selectedItem = null;
        }


        private void CloneTree(TreeViewItem treeNode, AElement arboriumNode)
        {
            if (treeNode != null && arboriumNode != null)
            {
                treeNode.Header = arboriumNode.ToString();
                _route[treeNode] = arboriumNode;

                foreach (AElement arboriumChild in arboriumNode.Children)
                {
                    TreeViewItem node = new TreeViewItem();
                    treeNode.Items.Add(node);
                    CloneTree(node, arboriumChild);
                }
            }
        }

        private static void NotImplemented()
        {
            MessageBox.Show("Functionality has not been implemented yet.", "Not implemented", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private bool IsItemSelected()
        {
            if (_arboriumTree == null || _tree == null || _selectedItem == null)
            {
                MessageBox.Show("No item selected.", "Error", MessageBoxButton.OK, MessageBoxImage.Hand);
                return false;
            }

            return true;
        }

        private static void EditNode(AElement selectedNode)
        {
            if (selectedNode.Data == null)
            {
                selectedNode.Data = new MemoryStream();
            }

            if (selectedNode.MetaData == null)
            {
                selectedNode.MetaData = new MemoryStream();
            }

            EditWindow editWindow = new EditWindow(selectedNode);
            editWindow.ShowDialog();

            if (selectedNode.Data.Length == 0)
            {
                selectedNode.Data = null;
            }

            if (selectedNode.MetaData.Length == 0)
            {
                selectedNode.MetaData = null;
            }
        }

        #endregion
    }
}
